﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TreeNode
{
    private Bounds                         m_Bounds;
    private List<SceneObject>              m_SObjects;
    private Dictionary<TreeType, TreeNode> m_TreeMap;
    private DivisionTreeType               m_DivisionTreeType;
    public  Bounds                         Bounds   => this.m_Bounds;
    public  List<SceneObject>              SObjects => this.m_SObjects;

    private int m_TreeOffset      = 0;
    private int m_TreeTargetIndex = 8;

    public int Count => this.m_TreeMap.Count;

    public TreeNode(DivisionTreeType type)
    {
        this.m_DivisionTreeType = type;
        this.m_TreeMap = new Dictionary<TreeType, TreeNode>();
        this.m_SObjects = new List<SceneObject>();
        
        //默认八叉树
        this.m_TreeTargetIndex = 8;
        this.m_TreeOffset = 0;

        if (this.m_DivisionTreeType != DivisionTreeType.Octree)
        {
            this.m_TreeTargetIndex = 12;
            this.m_TreeOffset = 8;
        }
    }

    public void SetBounds(Bounds bounds)
    {
        this.m_Bounds = bounds;
    }

    public void DivTree()
    {
        if (this.GetNullInitlize())
        {
            //分割
            if (this.m_DivisionTreeType == DivisionTreeType.Octree)
            {
                //分割八叉树
                this.DivOcTreeRectangle();
            }
        }
    }

    public bool Append(SceneObject sobject)
    {
        this.DivTree();
        if (this.m_Bounds.Contains(sobject.Bounds.max) && this.m_Bounds.Contains(sobject.Bounds.min))
        {
            TreeNode node = this.CheckIntersects(sobject.Bounds); //如果可放下，继续向下查找
            if (node != null)
            {
                this.DivTree();
                node.Append(sobject);
            }
            else
            {
                this.m_SObjects.Add(sobject);
            }
        }
        return true;
    }

    public void Iterator(Action<TreeNode> iteratorcallback)
    {
        if (iteratorcallback == null || this.m_TreeMap == null || this.m_TreeMap.Count <= 0) return;
        if (this.m_DivisionTreeType == DivisionTreeType.Octree)
        {
            for (int i = this.m_TreeOffset; i < this.m_TreeTargetIndex; i++)
            {
                TreeType treeType = (TreeType) (1 << i);
                if (this.m_TreeMap.ContainsKey(treeType))
                    iteratorcallback?.Invoke(this.m_TreeMap[treeType]);
            }
        }
    }

    private TreeNode CheckIntersects(Bounds bounds)
    {
        //遍历所有节点,必须包含 最大和最小，否则用父节点包含它
        for (int i = this.m_TreeOffset; i < this.m_TreeTargetIndex; i++)
        {
            TreeType treeType = (TreeType) (1 << i);
            if(!this.m_TreeMap.ContainsKey(treeType)) continue;
            TreeNode node     = this.m_TreeMap[treeType];
            if (node.Bounds.Contains(bounds.max) && node.Bounds.Contains(bounds.min))
            {
                return node;
            }
        }

        return null;
    }

    private void DivOcTreeRectangle()
    {
        this.m_TreeMap.Clear();

        Vector3 BoundsSize = this.m_Bounds.size * 0.5f;
        
        for (int i = this.m_TreeOffset; i < this.m_TreeTargetIndex; i++)
        {
            TreeType treeType = (TreeType) (1 << i);
            TreeNode treeNode = new TreeNode(this.m_DivisionTreeType);
            Vector3  center   = this.m_Bounds.center * 0.5f + this.GetCenter(treeType) * 0.5f;

            Bounds bounds = new Bounds(center, BoundsSize);
            treeNode.SetBounds(bounds);
            this.m_TreeMap[treeType] = treeNode;
        }
    }

    private bool GetNullInitlize()
    {
        return this.m_TreeMap.Count <= 0;
    }

    public void Recovery()
    {
        this.m_TreeMap.Clear();//目前先直接清理，后面可以考虑内存池，因为涉及引用。
    }
    
    private Vector3 GetCenter(TreeType treeType)
    {
        switch (treeType)
        {
            case TreeType.None:
                return Vector3.zero;
            case TreeType.Left_Bottom_Front:
                return this.m_Bounds.min;
            case TreeType.Left_Top_Front:
                return new Vector3(this.m_Bounds.min.x, this.m_Bounds.max.y, this.m_Bounds.min.z);
            case TreeType.Right_Top_Front:
                return new Vector3(this.m_Bounds.max.x, this.m_Bounds.max.y, this.m_Bounds.min.z);
            case TreeType.Right_Bottom_Front:
                return new Vector3(this.m_Bounds.max.x, this.m_Bounds.min.y, this.m_Bounds.min.z);
            case TreeType.Left_Bottom_Background:
                return new Vector3(this.m_Bounds.min.x, this.m_Bounds.min.y, this.m_Bounds.max.z);
            case TreeType.Left_Top_Background:
                return new Vector3(this.m_Bounds.min.x, this.m_Bounds.max.y, this.m_Bounds.max.z);
            case TreeType.Right_Top_Background:
                return this.m_Bounds.max;
            case TreeType.Right_Bottom_Background:
                return new Vector3(this.m_Bounds.max.x, this.m_Bounds.min.y, this.m_Bounds.max.z);
            case TreeType.Left_Bottom:
                break;
            case TreeType.Left_Top:
                break;
            case TreeType.Right_Top:
                break;
            case TreeType.Right_Bottom:
                break;
        }
        return Vector3.zero;
    }

}